#!/bin/sh -eu
#
# Copyright 2008 Mattias Norrby
#
# This file is part of Test Dept..
#
# Test Dept. is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Test Dept. is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Test Dept..  If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, you may use output from this script file
# that stems from this file without restriction as part of test cases.
# Specifically, if other programs use output from this script for
# constructing test-cases the output source code that stems from
# templates in this file does not by itself cause the resulting
# executable to be covered by the GNU General Public License.  This
# exception does not however invalidate any other reasons why the
# executable file might be covered by the GNU General Public License.

INVOCATION="`basename ${0}`"
SYMBOLS_FILE="${1:-}"

usage() {
    RETVAL="$1"
    echo "usage: $INVOCATION [symbols file]"
    echo "      ($INVOCATION reads nm(1) output and outputs C code for"
    echo "      a test binary containing all functions starting with \"test_\")"
    exit $RETVAL
}

err() {
    MSG="$1"
    echo "$INVOCATION: $MSG" >&2
    usage 2
}

case "$SYMBOLS_FILE" in
    -h|--help)
	usage 0
	;;
esac

if [ "$SYMBOLS_FILE" != "" ]; then
 [ -f "$SYMBOLS_FILE" ] || err "no readable file named \"$SYMBOLS_FILE\""
fi

cat <<EOF
#include <test-dept.h>

typedef void (*test_dept_test_function)();
typedef void (*test_dept_prepost_function)();

typedef struct {
  test_dept_test_function function;
  char* name;
} test_dept_test_function_data;
EOF
sed "s/ T _*/ T /g" $SYMBOLS_FILE | awk '
BEGIN { no_tests = 0; setup = "NULL"; teardown = "NULL" }
/ T test_/ { tests[$3]; no_tests = no_tests + 1 }
/ T set_*up$/ { setup = $3 }
/ T tear_*down$/ { teardown = $3 }
END {
  for (test in tests) {
    print "void " test "();"
  }
  if (setup != "NULL") {
    print "void " setup "();";
    setup = "&" setup;
  }
  if (teardown != "NULL") {
    print "void " teardown "();";
    teardown = "&" teardown;
  }

  print "test_dept_prepost_function setup_function = " setup ";"
  print "test_dept_prepost_function teardown_function = " teardown ";"
  print "test_dept_test_function_data test_functions[] = {"
  for (test in tests) {
    print "  {&" test ", \"" test "\"},"
  }
  print "};"
  print "int number_of_test_functions = " no_tests ";"
}
'
cat <<EOF2
int main(int argc, char *argv[]) {
  int test_no = 1;
  int saved_test_failures = 0;
  if (argc == 1) {
    int i = 0;
    while (i < number_of_test_functions)
      printf("%s\n", test_functions[i++].name);
  }
  for (test_no; test_no < argc; test_no++) {
    char* test_fun_name = argv[test_no];
    int test_fun = 0;
    for (; test_fun < number_of_test_functions; test_fun++)
      if (0 == strcmp(test_fun_name, test_functions[test_fun].name))
        break;
    if (test_fun < 0 || test_fun >= number_of_test_functions) {
      fprintf(stderr, "No test named %s\n", test_fun_name);
      test_dept_test_failures += 1;
      continue;
    }
    test_dept_test_function_data current = test_functions[test_fun];
    printf("%s:\n", current.name);
    fflush(stdout);
    saved_test_failures = test_dept_test_failures;
    if (setup_function)
      (*setup_function)();
    if (saved_test_failures == test_dept_test_failures)
    (*current.function)();
    if (teardown_function)
      (*teardown_function)();
  }
  return test_dept_test_failures;
}
EOF2
